番外篇的文章主要會分享一些影響我蠻多的框架或概念,今天來談論 redux 這個我很喜歡的函式庫。
redux 是我相當喜歡的一套狀態管理方式,它將整個狀態變化的架構分成三大部分:
store.getState()
拿狀態從這些描述上來看似乎過於抽象了,我們再來細談一些吧。
管理狀態一直是開發上的難題之一,尤其是在前端那麼多狀態共存的情況下,怎麼優雅地管理狀態就是一大問題,到底管理狀態難在哪裡?
今天會從前端狀態管理遇到的問題跟 redux 試圖解決的問題談狀態管理。
也因此在前端社群有不少狀態管理的方案持續出現,像是 flux、redux、mobX 等等,都是為了解決類似的問題。
在 redux 的世界中,想要改變狀態只有一個途徑,就是 dispatch 一個 action,同時確保有 reducer 做對應的狀態變化,除此之外別無他法,就連 store 當中也是只能從 getState
中拿取資料,沒辦法手動改寫。
這樣子確保了只有 action 才能夠讓狀態產生變化,在元件當中也只要 dispatch action,讓整個邏輯與操作變得簡單。
但要怎麼處理副作用?一個網頁應用正常來說都會有 Network 請求、Websocket 等操作,於是 redux 當中就有 middleware 的概念,在發送 action 前,可以透過 middleware 處理一切副作用(logging、async 等)。
像是 redux-observable、redux-saga、redux-thunk 等,都是讓非同步或具有副作用的操作可以與 redux 搭配使用,讓整個狀態管理更加清晰的方式。
這樣一來,在元件裡頭就不用寫各種 API 的處理,而是統一搬移到 middleware 這一層,除了實作元件上可以減少負擔之外也很好分工,讓開發者專注於開發元件,在適當的時機呼叫 action,串接 API 的部分就由另外一位開發者負責寫 reducer 與 action 等等。
redux 在設計上只是一個單純的 store 而已,並沒有和任何框架(如 React、Vue 等)有任何綁定,也因此 react-redux
就是為了整合 react 與 redux 而衍伸出來的。簡單來說就是幫你把 store 中的資料注入 react 元件當中。
有些人或許會問,為什麼還要大費周章再加上 react-redux
,而不直接用 store.subscribe
就好,何必還要寫什麼 mapStateToProps
與 mapStateToDispatch
呢?
對於 redux 來說,缺點也相當明顯,要定義各種 action 還有 reducer 是件相當惱人且枯燥的事,雖然有 redux-actions 之類的函式庫可以簡化,但還是一樣要做這些事情。
reducer 的執行會直接更新 store,也就是說每個 listener 都會被執行,雖然 react-redux 中做了許多優化,但檢查仍然需要時間,如果在短時間內大量送 action 在效能上或許就要不小的影響,而且這也代表著其他 action 的操作有可能會影響到整體更新的效能。
另外,當 reducer 一多,難免會增加不少 bundle size,這個時候要做 dynamic import 的話又需要額外做處理,而且也要確保在對應的元件載入的時候,對應的 reducer 也要一起載好,才不會拿不到 state。
一個簡單的 connect()
實現可以參考 Dan 的 gist。
理解背後的原理是什麼對於開發上是相當有幫助的,同樣的概念或許也可以用在其他地方上。最近越來越多「有了 xxx 就不需要 xxx」的聲音出現,如果不知道背後設計的原因與理念,也不了解歷史因素,那就是知識上的狂妄了。